package com.hifar.test.api.auth;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hifar.test.api.constant.AuthConstants;
import com.hifar.test.api.constant.AuthErrorCode;
import com.hifar.test.api.model.UnifiedResponse;
import com.hifar.test.api.util.AuthUtil;
import com.hifar.test.api.util.RSAUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Basic认证拦截器
 * 实现RSA加密的Basic认证机制
 * 
 * 认证流程：
 * 1. 用户名明文 + 密码RSA加密 → 用户名:加密密码
 * 2. 整体Base64编码 → Basic [Base64编码结果]
 */
@Component
public class BasicAuthInterceptor implements HandlerInterceptor {
    
    private static final Logger logger = LoggerFactory.getLogger(BasicAuthInterceptor.class);
    
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        
        // 跳过健康检查接口
        String requestURI = request.getRequestURI();
        if (requestURI.contains("/health") || requestURI.contains("/info")) {
            return true;
        }
        
        // 获取Authorization头
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null) {
            logger.warn("缺少Authorization头，客户端IP: {}", getClientIp(request));
            sendErrorResponse(response, AuthErrorCode.MISSING_AUTH_HEADER);
            return false;
        }
        
        if (!authHeader.startsWith("Basic ")) {
            logger.warn("认证头格式错误，客户端IP: {}, 认证头: {}", getClientIp(request), authHeader);
            sendErrorResponse(response, AuthErrorCode.INVALID_AUTH_FORMAT);
            return false;
        }
        
        try {
            // 验证Basic认证
            AuthErrorCode authResult = validateBasicAuthWithError(authHeader);
            if (authResult == null) {
                logger.info("Basic认证验证成功，客户端IP: {}", getClientIp(request));
                return true;
            } else {
                logger.warn("Basic认证验证失败，错误码: {}, 客户端IP: {}", authResult.getCode(), getClientIp(request));
                sendErrorResponse(response, authResult);
                return false;
            }
        } catch (Exception e) {
            logger.error("认证处理异常，客户端IP: {}", getClientIp(request), e);
            sendErrorResponse(response, AuthErrorCode.AUTH_PROCESS_ERROR);
            return false;
        }
    }
    
    /**
     * 验证Basic认证（带错误码）
     * 
     * @param authHeader 认证头
     * @return 错误码，null表示验证成功
     */
    private AuthErrorCode validateBasicAuthWithError(String authHeader) {
        try {
            // 提取凭据
            String credentials = AuthUtil.extractCredentials(authHeader);
            
            if (credentials == null || credentials.trim().isEmpty()) {
                logger.warn("凭据为空");
                return AuthErrorCode.EMPTY_CREDENTIALS;
            }
            
            String[] parts = credentials.split(":", 2);
            
            if (parts.length != 2) {
                logger.warn("凭据格式不正确，凭据: {}", credentials);
                return AuthErrorCode.INVALID_CREDENTIALS_FORMAT;
            }
            
            String username = parts[0];
            String encryptedPassword = parts[1];
            
            // 验证用户名
            if (username == null || username.trim().isEmpty()) {
                logger.warn("用户名为空");
                return AuthErrorCode.INVALID_USERNAME;
            }
            
            if (!AuthConstants.DEFAULT_USERNAME.equals(username)) {
                logger.warn("用户名不正确: {}", username);
                return AuthErrorCode.INVALID_USERNAME;
            }
            
            // 验证密码
            if (encryptedPassword == null || encryptedPassword.trim().isEmpty()) {
                logger.warn("密码为空");
                return AuthErrorCode.INVALID_PASSWORD;
            }
            
            // 使用私钥解密密码进行验证
            return validatePasswordWithDecryptionError(encryptedPassword);
            
        } catch (IllegalArgumentException e) {
            logger.error("Basic认证验证异常 - 参数错误", e);
            return AuthErrorCode.INVALID_BASE64;
        } catch (Exception e) {
            logger.error("Basic认证验证异常", e);
            return AuthErrorCode.AUTH_PROCESS_ERROR;
        }
    }
    
    /**
     * 使用私钥解密验证密码（带错误码）
     * 
     * @param encryptedPassword 加密后的密码
     * @return 错误码，null表示验证成功
     */
    private AuthErrorCode validatePasswordWithDecryptionError(String encryptedPassword) {
        try {
            // 使用私钥解密密码
            String decryptedPassword = RSAUtil.decryptPassword(encryptedPassword);
            
            // 比较解密后的密码与默认密码
            boolean isValid = AuthConstants.DEFAULT_PASSWORD.equals(decryptedPassword);
            
            if (isValid) {
                logger.info("密码验证成功");
                return null; // 验证成功
            } else {
                logger.warn("密码验证失败，解密后的密码: {}", decryptedPassword);
                return AuthErrorCode.INVALID_PASSWORD;
            }
        } catch (Exception e) {
            logger.error("密码解密验证异常", e);
            if (e.getMessage().contains("RSA") || e.getMessage().contains("decrypt")) {
                return AuthErrorCode.RSA_DECRYPT_ERROR;
            } else {
                return AuthErrorCode.PASSWORD_DECRYPT_ERROR;
            }
        }
    }
    
    /**
     * 发送错误响应
     * 
     * @param response HTTP响应对象
     * @param errorCode 错误码
     */
    private void sendErrorResponse(HttpServletResponse response, AuthErrorCode errorCode) {
        try {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            
            // 使用指定的认证失败响应格式
            String jsonResponse = createAuthFailureResponse(errorCode);
            
            response.getWriter().write(jsonResponse);
            response.getWriter().flush();
        } catch (Exception e) {
            logger.error("发送错误响应失败", e);
            try {
                response.getWriter().write("{\"status\":-1,\"message\":\"认证失败：系统错误\"}");
            } catch (Exception ex) {
                logger.error("发送默认错误响应失败", ex);
            }
        }
    }
    
    /**
     * 创建认证失败响应
     * 
     * @param errorCode 错误码
     * @return JSON响应字符串
     */
    private String createAuthFailureResponse(AuthErrorCode errorCode) {
        try {
            // 创建认证失败响应格式
            java.util.Map<String, Object> response = new java.util.HashMap<>();
            response.put("status", -1);
            response.put("message", errorCode.getMessage());
            
            java.util.Map<String, Object> data = new java.util.HashMap<>();
            data.put("successCount", 0);
            
            java.util.List<java.util.Map<String, Object>> failedData = new java.util.ArrayList<>();
            java.util.Map<String, Object> failureItem = new java.util.HashMap<>();
            failureItem.put("task_id", "AUTH_ERROR");
            failureItem.put("type", "failure");
            failureItem.put("reason", errorCode.getMessage());
            failedData.add(failureItem);
            
            data.put("failedData", failedData);
            response.put("data", data);
            
            return objectMapper.writeValueAsString(response);
        } catch (Exception e) {
            logger.error("创建认证失败响应失败", e);
            return "{\"status\":-1,\"message\":\"认证失败：系统错误\"}";
        }
    }
    
    /**
     * 获取客户端IP地址
     * 
     * @param request HTTP请求对象
     * @return 客户端IP地址
     */
    private String getClientIp(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
        
        return request.getRemoteAddr();
    }
}
